//
//  BusLogic.cpp
//  sad
//
//  Created by Christopher Kemsley on 2/23/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#include "BusInterface.hpp"
#include "SystemCDefinitions.hpp"

#include "ModuleFactory.hpp"

#include "Settings.hpp"
#include "URL.hpp"
#include "Codec.hpp"
#include "Log.hpp"
#include "PubSub.hpp"
#include "Exception.hpp"

#include "SingleFireSignal.hpp"

#include <list>

#include "Statistics.hpp"

#include "bus_nathan.h"


#define	SendNotification(notif)		notif . notify ( 0 , kSCIntervalSeconds ) ;
#define	SetAndNotify(ivar,value)	{ ivar=value ;\
	Log::states("LogicalBus")<<"**** Setting " SymbolToString(ivar) " to " << value ;\
	SendNotification ( ivar ## DidChange ) ; }



BusNamespaceBegin


struct	ActiveRequest : public Request
{
	Address	senderID ;
	
	ActiveRequest	( Request const & inRequest , Address inAddress )
	:	Request		( inRequest )
	,	senderID	( inAddress )
		{
		if ( inAddress == 0 )
			ThrowException ( "ActiveRequest" , "ActiveRequest cannot have null sender-address" , __FILE__,__LINE__ ) ;
		}
	ActiveRequest	()
	:	Request		()
	,	senderID	( 0 )
		{ }
	ActiveRequest	( ActiveRequest const & inCopy )
	:	Request		( inCopy )
	,	senderID	( inCopy.senderID )
		{
		if ( senderID == 0 )
			ThrowException ( "ActiveRequest" , "ActiveRequest cannot have null sender-address" , __FILE__,__LINE__ ) ;
		}
	
	void	operator=	( ActiveRequest const & inCopy )
		{
		Request::operator= ( inCopy ) ;
		senderID = inCopy.senderID ;
		
		}
	
	friend std::ostream& operator<< ( std::ostream & stream , ActiveRequest const & request ) ;
} ;

std::ostream& operator<< ( std::ostream & stream , ActiveRequest const & request )
	{
	stream << "<ActiveRequest" ;
	stream << " mode=" << ( (request.operation==Bus::kOperationRead) ? "Read" : "Write" ) ;
	stream << " address=" << request.baseAddress ;
	stream << " length=" << request.blockLength ;
	stream << " senderAddress=" << request.senderID ;
	stream << " uniqueID=" << request.uniqueID ;
	return stream << ">" ;
	}






struct	LogicalBusSettings : public Settings
{
	std::string	masterName ;
	std::string	slaveName ;
	
	LogicalBusSettings ( std::string const & name )
	:	Settings(name)
	,	masterName		( )
	,	slaveName		( )
		{
		add ( "masterName" , masterName ) ;
		add ( "slaveName" , slaveName ) ;
		}
	
	virtual void validate ()
		{
		if ( masterName.size() == 0 )
			Log::error("LogicalBusSettings") << "Master-interface name's length is 0" ;
		if ( slaveName.size() == 0 )
			Log::error("LogicalBusSettings") << "Slave-interface name's length is 0" ;
		}
	
	
} ;



// Enumeration (as strings, so we can print them out easily)
char const* const	kStateIdle					=	 "<State: idle>" ;
char const* const	kStateWaitingForAcknowledge	=	 "<State: waiting for ack>" ;
char const* const	kStateNoAcknowledgeTimeout	=	 "<State: timed out waiting for ack>" ;
char const* const	kStateReceivedAcknowledge	=	 "<State: received ack & transferring>" ;


BusNamespaceEnd










using namespace Bus ;











struct	LogicalBus : public ConfiguredModel<LogicalBusSettings> , virtual public MasterInterface , virtual public SlaveInterface
{
	
	
	
	
	/* Hey world: here's our interface! */
	Publication<MasterInterface>	mMasterPub ;
	Publication<SlaveInterface>		mSlavePub ;
	
	
	NathanNamespace::bus			mChasse ; // get it?
	
	
	
	SC_HAS_PROCESS(LogicalBus) ;
	
	LogicalBus ( ModelVariant const & name )
	:	ConfiguredModel<LogicalBusSettings>	( name )
	,	mMasterPub()
	,	mSlavePub()
	,	mChasse (( name.instanceName + "_chasse" ).c_str())
		{
		MasterInterface*	thisMaster	=	this ;
		mMasterPub = mConfig.masterName ;
		mMasterPub = thisMaster ;
		
		SlaveInterface*		thisSlave	=	this ;
		mSlavePub = mConfig.slaveName ;
		mSlavePub = thisSlave ;
		}
	
	
	
	
	
	
	
	/* Master Synchronization */
	
	virtual void	request		( Identifier const & inSender , Request const & inRequest )
		{
		mChasse . Request ( inSender , inRequest.baseAddress , inRequest.operation , inRequest.blockLength ) ;
		}
	virtual bool	waitForAcknowledge	( Identifier const & sender )
		{
		return mChasse . WaitForAcknowledge ( sender ) ;
		}
	
	
	/* Slave Synchronization */
	
	virtual void	waitForNewRequest	( Request & outRequest )
		{
		mChasse . Listen ( outRequest.baseAddress , outRequest.operation , outRequest.blockLength ) ;
		}
	virtual void	acknowledgeRequest	()
		{
		mChasse . Acknowledge () ;
		}
	
	
	
	
	/* R/W Synchronization */
	
	virtual void	readWord	( Word & word )
		{
		unsigned value ;
		if ( mChasse.currentOp == kOperationRead )
			{
			mChasse . ReadData ( value ) ;
			word = value ;
			}
		else
			{
			mChasse . ReceiveWriteData ( value ) ;
			word = value ;
			}
		}
	virtual void	writeWord	( Word const & word )
		{
		unsigned value = word ;
		if ( mChasse.currentOp == kOperationRead )
			{
			mChasse . SendReadData ( value ) ;
			}
		else
			{
			mChasse . WriteData ( value ) ;
			}
		}
	
	
	
	
	
	
	
	
} ;



TypedModuleMaker<LogicalBus>	_LogicalBus ( "Bus.abstract.timed" ) ;
